<!-- 
/**
* @author: ptt
* @desc: 滚动表格
* @date: 2023/12/12
*/ -->
<template>
    <div class="ptt-table" ref="ptt-table">
        <div class="ptt-table__wrapper ptt-scroll-x">
            <!-- 头部 -->
            <div class="ptt-table__header" :style="{ width: conWidth }">
                <table>
                    <colgroup>
                        <col
                            v-for="w in colsWidth"
                            :key="timestamp"
                            :width="w"
                        />
                    </colgroup>
                    <thead>
                        <slot name="header">
                            <tr class="ptt-table__header__row">
                                <th v-for="th in header" :key="timestamp">
                                    <div
                                        class="flex-aic th-cell"
                                        :class="setAlign(th.align)"
                                    >
                                        <span v-html="th.label"> </span>

                                        <div v-if="th.sort" class="sort-arrow">
                                            <!-- 上箭头 -->
                                            <i
                                                @click="sort(th.prop, $event)"
                                                class="up-arrow"
                                            ></i>
                                            <!-- 下箭头 -->
                                            <i
                                                @click="sort(th.prop, $event)"
                                                class="down-arrow"
                                            ></i>
                                        </div>
                                    </div>
                                </th>
                            </tr>
                        </slot>
                    </thead>
                </table>
            </div>

            <!-- 内容 -->
            <div
                class="ptt-table__content ptt-scroll-y"
                :style="{ width: conWidth }"
            >
                <table>
                    <colgroup>
                        <col
                            v-for="w in colsWidth"
                            :key="timestamp"
                            :width="w"
                        />
                    </colgroup>
                    <tbody>
                        <slot>
                            <tr
                                v-for="(row, idx) in tableData"
                                :key="timestamp"
                            >
                                <td
                                    v-for="(th, i) in rendTd(row)"
                                    :key="timestamp"
                                    :rowspan="row[th.prop + '_rowspan']"
                                >
                                    <slot
                                        :name="th.prop"
                                        :row="row"
                                        :prop="th"
                                        :$index="row.$index"
                                    >
                                        <div
                                            class="cell"
                                            :class="setAlign(th.align)"
                                        >
                                            <span
                                                :title="
                                                    th.showTitle
                                                        ? row[th.prop]
                                                        : ''
                                                "
                                            >
                                                {{
                                                    $handleStr.setDefault(
                                                        row[th.prop]
                                                    )
                                                }}
                                            </span>
                                        </div>
                                    </slot>
                                </td>
                            </tr>
                        </slot>
                    </tbody>
                </table>
                <NoData :data="tableData">
                    <slot name="empty">暂无数据 </slot>
                </NoData>
            </div>
        </div>
    </div>
</template>

<script>
import { tableSort } from '@/utils/sort.js';
import { mergeRow, compareMerge } from '@/utils/mergeTable.js';

export default {
    props: {
        // 数据项
        data: {
            type: Array,
            require: true
            // default: () => {
            //     return [
            //         {
            //             DSMC: '无锡市',
            //             SZZK: 'Ⅱ类',
            //             CBSL: 2,
            //             SYCBW: '总磷',
            //             CBL: '44.6',
            //             CBLDW: '%'
            //         }
            //     ];
            // }
        },
        // 表头项(每一列字段集合)
        header: {
            type: Array,
            require: true
            // default: [{ label: '超标率<br/> (%)', prop: 'DSMC' ,sort:true , colWidth:'200px'}]  //必填项：label,prop  可选项： sort(能否排序,按大小排序),colWidth(列宽),align(字段对齐方式),showTitle(鼠标悬停显示提示文字)
        },
        // 表格内容宽度（大于视口宽度时可横向滚动） px/%
        'con-width': String,
        // 表格tbody高度
        height: String,
        // 是否带有垂直边框（merge传了type也会加入垂直边框）
        border: {
            type: Boolean,
            default: false
        },
        // 是否合并单元格
        merge: {
            type: Object,
            default: () => {
                return {
                    // type:'row' , //合并行（比如第一行和第二行）
                    // props:['xh','name'] // 需要合并的表头属性名
                };
            }
        }
    },
    data() {
        return {
            colsWidth: [], // 列宽
            timestamp: Date.now(), //v-for的key值,时间戳
            tableData: []
        };
    },
    mounted() {
        this.calculateColsWidth();
    },
    watch: {
        data: {
            deep: true,
            handler(newVal, oldVal) {
                this.tableData = JSON.parse(JSON.stringify(newVal));
            }
        },
        tableData: {
            handler(newVal, oldVal) {
                if (this.merge.type) {
                    this.mergeTable();
                }
                // 如果有合并单元格，追加纵向边框
                if (this.border || this.merge.type) {
                    this.$nextTick(() => {
                        const tds = document.querySelectorAll(
                            '.ptt-table__content td'
                        );
                        tds.forEach(item => {
                            item.classList.add('border-both');
                        });
                    });
                }
                this.$emit('dataChange', newVal);
            }
        }
    },
    methods: {
        /**
         * @desc: 计算列宽
         * @param:
         * @returns: */
        calculateColsWidth() {
            // 提取列宽
            const cols = this.header
                .map(item => item.colWidth)
                .filter(colW =>
                    this.$handleStr.hasValue(colW) ? colW + '' : ''
                );
            const colsLen = cols.length;
            const headLen = this.header.length;
            // 每列都指定了宽度
            if (colsLen && colsLen === headLen) {
                this.colsWidth = cols;
            }
            // 某些列指定了宽度
            else if (colsLen) {
                this.$nextTick(() => {
                    let tableW = this.$refs['ptt-table'].clientWidth;
                    // 减去指定的宽度
                    cols.map(colW => {
                        if (colW.includes('%')) {
                            tableW -= (colW.split('%')[0] / 100) * tableW;
                        } else if (colW.includes('px')) {
                            tableW = tableW - colW.split('px')[0];
                        }
                    });
                    // 计算剩余平均宽度
                    let surLen = headLen - colsLen;
                    const everW = tableW / surLen + 'px';
                    this.colsWidth = this.header.map(item => {
                        const colW = item.colWidth;
                        return this.$handleStr.hasValue(colW) ? colW : everW;
                    });
                });
            }
            // 每列都没指定宽度
            else {
                // 设置每列的平均百分比宽度
                const everPerW = 100 / headLen + '%';
                this.colsWidth = this.header.map(item => everPerW);
            }
        },
        /**
         * @desc: 表格排序
         * @param: 当前排序的字段  事件对象
         * @returns: */
        sort(key, e) {
            const classList = e.target.classList;

            // 取消排序时 填充原数据到表格中
            if (classList.contains('on')) {
                classList.remove('on');
                // 排序后重新追加序号
                this.data.map((item, index) => (item.$index = index + 1));
                this.tableData = this.data;
            } else {
                // 移除之前的选中项
                const arrowDoms = document.querySelectorAll('.sort-arrow');
                arrowDoms.forEach(dom => {
                    for (let i = 0; i < dom.children.length; i++) {
                        dom.children[i].classList.remove('on');
                    }
                });
                classList.add('on');
                const type = classList.contains('up-arrow') ? 'up' : 'down';

                // 对数据进行排序
                let sortArr = tableSort(this.tableData, key, type);
                // 追加排序号
                sortArr.map((item, index) => {
                    item.$index = index + 1;
                });
                this.tableData = sortArr;
            }
            const pams = {};
            pams[key] = this.tableData;
        },
        /**
         * @desc: 设置单元格水平对齐方式
         * @param: 当前字段的对齐方式【String】
         * @returns: class类名*/
        setAlign(align) {
            switch (align) {
                case 'left':
                    return 'flex-jcs';
                    break;
                case 'center':
                    return 'flex-jcc';
                    break;
                case 'right':
                    return 'flex-end';
                    break;

                default:
                    return 'flex-jcc';
                    break;
            }
        },
        /**
         * @desc: 合并单元格
         * @param:
         * @returns:  */
        mergeTable() {
            const type = this.merge.type;
            const mergeProps = this.merge.props;
            const referProp = this.merge.referProp;
            const referMergeProps = this.merge.referMergeProps;
            const allProps = this.header.map(item => item.prop);
            if (type == 'row') {
                mergeRow(this.tableData, allProps, mergeProps);
                if (referProp) {
                    compareMerge(
                        this.tableData,
                        referProp,
                        referMergeProps,
                        true
                    );
                }
            }
        },
        /**
         * @desc: 渲染td
         * @param: row【Object】每一行的数据
         * @returns:  每一行的td数量【Array】*/
        rendTd(row) {
            if (this.merge.type) {
                return this.header.filter(
                    item => row[item.prop + '_rowspan'] > 0
                );
            } else {
                return this.header;
            }
        }
    }
};
</script>

<style lang="scss" scoped>
.ptt-table {
    table {
        width: 100%;
    }
    // 头部表格
    .ptt-table__header {
        th {
            .th-cell {
                padding: 0 10px;
                .icon-sort {
                    cursor: pointer;
                    width: 16px;
                    height: 13px;
                }
            }
        }
    }

    // 内容表格
    .ptt-table__content {
        height: v-bind('height');
        overflow: auto;

        td .cell {
            padding: 0 10px;
            word-break: break-all;
        }
        td.border-both {
            border-left: 1px solid rgba(225, 225, 225, 0.6);
            border-right: 1px solid rgba(225, 225, 225, 0.6);
        }
    }
}

//排序箭头
.sort-arrow {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    justify-content: space-between;
    height: 21px;
    margin: 0 4px;
    cursor: pointer;

    .up-arrow,
    .down-arrow {
        width: 0;
        height: 0;
        border: 5px solid transparent;
    }
    // 上箭头
    .up-arrow {
        border-bottom-color: #eee;
        &.on {
            border-bottom-color: #409eff;
        }
    }
    // 下箭头
    .down-arrow {
        border-top-color: #eee;
        &.on {
            border-top-color: #409eff;
        }
    }
}
</style>
